package tagdb.ui;

import com.compomics.util.experiment.biology.Peptide;
import com.compomics.util.experiment.biology.ions.PeptideFragmentIon;
import com.compomics.util.experiment.identification.SpectrumAnnotator;
import com.compomics.util.experiment.identification.matches.IonMatch;
import com.compomics.util.experiment.identification.matches.ModificationMatch;
import com.compomics.util.experiment.massspectrometry.Charge;
import com.compomics.util.experiment.massspectrometry.MSnSpectrum;
import com.compomics.util.experiment.massspectrometry.Peak;
import com.compomics.util.experiment.massspectrometry.Precursor;
import com.compomics.util.gui.spectrum.SpectrumPanel;
import com.compomics.util.preferences.AnnotationPreferences;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
import no.uib.jsparklines.renderers.JSparklinesBarChartTableCellRenderer;
import org.jdesktop.swingx.JXMultiSplitPane;
import org.jdesktop.swingx.JXTable;
import org.jdesktop.swingx.JXTitledPanel;
import org.jdesktop.swingx.MultiSplitLayout;
import org.jdesktop.swingx.hyperlink.AbstractHyperlinkAction;
import org.jdesktop.swingx.renderer.DefaultTableRenderer;
import org.jdesktop.swingx.renderer.HyperlinkProvider;
import org.jdesktop.swingx.renderer.JXRendererHyperlink;
import org.jfree.chart.plot.PlotOrientation;
import tagdb.algorithm.match.PeptideSpectrumMatch;
import tagdb.io.MascotGenericFile;
import tagdb.model.PeptideHit;
import tagdb.model.ProteinFamilyHit;
import tagdb.model.ProteinHit;
import tagdb.model.TagSearchResult;
import tagdb.ui.util.PanelFactory;
import tagdb.ui.util.TableConfig;

import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.net.URI;
import java.util.*;
import java.util.List;
import java.util.Map.Entry;

public class TagSearchResultPanel extends JPanel {

    private JXTable proteinTbl;
    private JXTable peptideTbl;
    private JXTable psmTbl;
    private TagSearchResult tagSearchResult;
    private JPanel spectrumJPanel;
    private SpectrumPanel specPnl;
    private Map<String, MascotGenericFile> querySpectra;
    private JXTable proteinFamTbl;
    private String familyName;
    private CellConstraints cc;
    private Map<Integer, PeptideSpectrumMatch> indexPsmMap;
    private MainFrame mainFrame;
    private List<String> proteinFamilyTableToolTips;
    private List<String> proteinTableToolTips;
    private List<String> peptideTableToolTips;
    private List<String> psmTableToolTips;
    private JPanel spectrumOverviewPnl;

    /**
     * Constructor for a database results panel.
     * 
     * @param mainFrame a reference to the main frame
     */
    public TagSearchResultPanel(MainFrame mainFrame) {
        this.mainFrame = mainFrame;
        initComponents();
    }

    /**
     * Initialize the components.
     */
    private void initComponents() {
        cc = new CellConstraints();
        // Define layout
        this.setLayout(new FormLayout("5dlu, p:g, 5dlu", "5dlu, f:p:g, 5dlu"));

        final JPanel proteinPnl = new JPanel();
        proteinPnl.setLayout(new FormLayout("5dlu, p:g, 5dlu", "5dlu, f:p:g, 5dlu"));

        final JPanel proteinFamPnl = new JPanel();
        proteinFamPnl.setLayout(new FormLayout("5dlu, p:g, 5dlu", "5dlu, f:p:g, 5dlu"));

        // Setup tables
        setupProteinFamilyTableProperties();
        setupProteinTableProperties();
        setupPeptideTableProperties();
        setupPsmTableProperties();

        // JPanel upperPanel
        final JPanel topPanel = new JPanel(new FormLayout("5dlu, p, 5dlu, p, 5dlu", "p"));

        // Scroll panes
        JScrollPane proteinTableScp = new JScrollPane(proteinTbl);
        proteinTableScp.setPreferredSize(new Dimension(100, 150));
        JScrollPane peptideTableScp = new JScrollPane(peptideTbl);
        peptideTableScp.setPreferredSize(new Dimension(100, 120));
        JScrollPane psmTableScp = new JScrollPane(psmTbl);
        psmTableScp.setPreferredSize(new Dimension(100, 150));

        // Family table scrollpane
        JScrollPane familyTableScp = new JScrollPane(proteinFamTbl);
        familyTableScp.setPreferredSize(new Dimension(100, 150));
        proteinFamPnl.add(familyTableScp, cc.xy(2, 2));

        // Protein families panel
        JXTitledPanel protFamTtlPnl = PanelFactory.createTitledPanel("Protein Families", proteinFamPnl);

        topPanel.add(protFamTtlPnl, cc.xy(2, 1));
        proteinPnl.add(proteinTableScp, cc.xy(2, 2));

        JXTitledPanel protTtlPnl = PanelFactory.createTitledPanel("Proteins", proteinPnl);

        topPanel.add(protTtlPnl, cc.xy(4, 1));

        // Peptide panel
        final JPanel peptidePnl = new JPanel();
        peptidePnl.setLayout(new FormLayout("5dlu, p:g, 5dlu", "5dlu, f:p:g, 5dlu"));

        peptidePnl.add(peptideTableScp, cc.xy(2, 2));

        JXTitledPanel pepTtlPnl = PanelFactory.createTitledPanel("Peptides", peptidePnl);

        // PSM panel
        final JPanel psmPanel = new JPanel();
        psmPanel.setLayout(new FormLayout("5dlu, p:g, 5dlu", "5dlu, f:p:g, 5dlu"));
        psmPanel.add(psmTableScp, cc.xy(2, 2));

        JXTitledPanel psmTtlPnl = PanelFactory.createTitledPanel("Peptide-Spectrum-Matches", psmPanel);

        // Peptide and Psm Panel
        JPanel pepPsmPnl = new JPanel(new FormLayout("p:g", "f:p:g, 5dlu, f:p:g"));

        pepPsmPnl.add(pepTtlPnl, cc.xy(1, 1));
        pepPsmPnl.add(psmTtlPnl, cc.xy(1, 3));

        // Build the spectrum overview panel
        spectrumOverviewPnl = new JPanel(new BorderLayout());

        spectrumJPanel = new JPanel();
        spectrumJPanel.setLayout(new BoxLayout(spectrumJPanel, BoxLayout.LINE_AXIS));
        spectrumJPanel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
        spectrumJPanel.add(new SpectrumPanel(new double[]{0.0, 100.0}, new double[]{100.0, 0.0}, 0.0, "", ""));
        spectrumJPanel.setPreferredSize(new Dimension(100, 200));
        spectrumOverviewPnl.add(spectrumJPanel, BorderLayout.CENTER);

        JXTitledPanel specTtlPnl = PanelFactory.createTitledPanel("Spectrum Viewer", spectrumOverviewPnl);

        // set up multi split pane
        String layoutDef =
                "(COLUMN (ROW weight=1.0 (LEAF weight=0.34 name=family) (LEAF weight=0.66 name=protein))(ROW weight=0.0 (COLUMN weight=0.3 (LEAF weight=0.5 name=peptide) (LEAF weight=0.5 name=psm)) (LEAF weight=0.7 name=plot)))";
        MultiSplitLayout.Node modelRoot = MultiSplitLayout.parseModel(layoutDef);

        final JXMultiSplitPane multiSplitPane = new JXMultiSplitPane();
        multiSplitPane.setDividerSize(12);
        multiSplitPane.getMultiSplitLayout().setModel(modelRoot);
        multiSplitPane.add(protFamTtlPnl, "family");
        multiSplitPane.add(protTtlPnl, "protein");
        multiSplitPane.add(pepTtlPnl, "peptide");
        multiSplitPane.add(psmTtlPnl, "psm");
        multiSplitPane.add(specTtlPnl, "plot");

        this.add(multiSplitPane, cc.xy(2, 2));
    }
    
    /**
     * Display or hide the annotation menubar.
     */
    public void displayAnnotationMenu() {
        if (spectrumOverviewPnl.getComponentCount() == 2) {
            spectrumOverviewPnl.remove(1);
        }

        spectrumOverviewPnl.add(mainFrame.getAnnotationMenuBar(), BorderLayout.SOUTH);   
    }


    /**
     * This method sets up the protein family table.
     */
    private void setupProteinFamilyTableProperties() {
        // Protein table
        final DefaultTableModel proteinFamilyTblMdl = new DefaultTableModel() {
            // instance initializer block
            {
                setColumnIdentifiers(new Object[]{
                        "#",                 //0
                        "Annotation",         //1
                        "Spectral Count"}); // 2
            }

            public boolean isCellEditable(int row, int col) {
                return false;
            }

            public Class<?> getColumnClass(int columnIndex) {
                switch (columnIndex) {
                    case 0:
                    case 2:
                        return Integer.class;
                    case 1:
                        return String.class;
                    default:
                        return String.class;
                }
            }
        };

        proteinFamilyTableToolTips = new ArrayList<String>();
        proteinFamilyTableToolTips.add("Protein Family Index");
        proteinFamilyTableToolTips.add("Protein Family Annotation");
        proteinFamilyTableToolTips.add("Number of Spectra");

        proteinFamTbl = new JXTable(proteinFamilyTblMdl) {
            protected JTableHeader createDefaultTableHeader() {
                return new JTableHeader(columnModel) {
                    public String getToolTipText(MouseEvent e) {
                        java.awt.Point p = e.getPoint();
                        int index = columnModel.getColumnIndexAtX(p.x);
                        int realIndex = columnModel.getColumn(index).getModelIndex();
                        String tip = (String) proteinFamilyTableToolTips.get(realIndex);
                        return tip;
                    }
                };
            }
        };

        // adjust column widths
        TableConfig.setColumnWidths(proteinFamTbl, new double[]{1, 4.0, 5.0});

        // Create table model
        final TableColumnModel tcm = proteinFamTbl.getColumnModel();
        tcm.getColumn(0).setCellRenderer(new TableConfig.CustomTableCellRenderer(SwingConstants.RIGHT));
        tcm.getColumn(2).setCellRenderer(new TableConfig.CustomTableCellRenderer(SwingConstants.LEFT));

        // Sort the protein family table by the number of spectral counts
        proteinFamTbl.setAutoCreateRowSorter(true);
        proteinFamTbl.getRowSorter().toggleSortOrder(2);
        proteinFamTbl.getRowSorter().toggleSortOrder(2);

        proteinFamTbl.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent evt) {
                refreshProteinTable();
            }
        });

        // Only one row is selectable
        proteinFamTbl.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        proteinFamTbl.setSelectionBackground(new Color(130, 207, 250));

        // Add nice striping effect
        proteinFamTbl.addHighlighter(TableConfig.getSimpleStriping());

        // Sets the column control visible.
        proteinFamTbl.setColumnControlVisible(true);
    }

    /**
     * This method sets up the protein results table.
     */
    private void setupProteinTableProperties() {
        // Protein table
        final DefaultTableModel proteinTblMdl = new DefaultTableModel() {
            // instance initializer block
            {
                setColumnIdentifiers(new Object[]{
                        "#",                 //0
                        "Accession",         //1
                        "Description",      //2
                        "Species",             //3
                        "MW [kDa]"});
            }        //4

            public boolean isCellEditable(int row, int col) {
                return false;
            }

            public Class<?> getColumnClass(int columnIndex) {
                switch (columnIndex) {
                    case 0:
                        return Integer.class;
                    case 4:
                        return Double.class;
                    default:
                        return String.class;
                }
            }
        };

        proteinTableToolTips = new ArrayList<String>();
        proteinTableToolTips.add("Protein Index");
        proteinTableToolTips.add("Protein Accession");
        proteinTableToolTips.add("Protein Description");
        proteinTableToolTips.add("Protein Species");
        proteinTableToolTips.add("Protein Molecular Weight (kDa)");

        proteinTbl = new JXTable(proteinTblMdl) {
            protected JTableHeader createDefaultTableHeader() {
                return new JTableHeader(columnModel) {
                    public String getToolTipText(MouseEvent e) {
                        java.awt.Point p = e.getPoint();
                        int index = columnModel.getColumnIndexAtX(p.x);
                        int realIndex = columnModel.getColumn(index).getModelIndex();
                        String tip = (String) proteinTableToolTips.get(realIndex);
                        return tip;
                    }
                };
            }
        };


        // adjust column widths
        TableConfig.setColumnWidths(proteinTbl, new double[]{1, 3.0, 6.0, 5.0, 4.0});

        // Create table model
        final TableColumnModel tcm = proteinTbl.getColumnModel();

        AbstractHyperlinkAction<URI> linkAction = new AbstractHyperlinkAction<URI>() {
            public void actionPerformed(ActionEvent ev) {
                try {
                    Desktop.getDesktop()
                            .browse(new URI("http://www.uniprot.org/uniprot/" + target));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };


        tcm.getColumn(1).setCellRenderer(new DefaultTableRenderer(new HyperlinkProvider(linkAction)) {
            public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
                Component comp = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
                JXRendererHyperlink compLabel = (JXRendererHyperlink) comp;
                compLabel.setHorizontalAlignment(SwingConstants.CENTER);
                return compLabel;
            }
        });
        tcm.getColumn(2).setCellRenderer(new TableConfig.CustomTableCellRenderer(SwingConstants.LEFT));
        tcm.getColumn(3).setCellRenderer(new TableConfig.CustomTableCellRenderer(SwingConstants.LEFT));
        tcm.getColumn(4).setCellRenderer(new TableConfig.CustomTableCellRenderer(SwingConstants.CENTER, "0.000"));

        // Sort the protein table by spectral count
        proteinTbl.setAutoCreateRowSorter(true);

        proteinTbl.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent evt) {
                refreshPeptideTable();
            }
        });

        // Only one row is selectable
        proteinTbl.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        proteinTbl.setSelectionBackground(new Color(130, 207, 250));

        // Add nice striping effect
        proteinTbl.addHighlighter(TableConfig.getSimpleStriping());

        // Sets the column control visible.
        proteinTbl.setColumnControlVisible(true);
    }

    private void setupPeptideTableProperties() {
        // Peptide table
        final TableModel peptideTableMdl = new DefaultTableModel() {
            // instance initializer block
            {
                setColumnIdentifiers(new Object[]{"#", "Sequence", "No. Spectra"});
            }

            public boolean isCellEditable(int row, int col) {
                return false;
            }

            public Class<?> getColumnClass(int columnIndex) {
                switch (columnIndex) {
                    case 0:
                    case 2:
                        return Integer.class;
                    case 1:
                        return String.class;
                    default:
                        return String.class;
                }
            }
        };

        peptideTableToolTips = new ArrayList<String>();
        peptideTableToolTips.add("Peptide Index");
        peptideTableToolTips.add("Pepitde Sequence");
        peptideTableToolTips.add("Number of Spectra");

        peptideTbl = new JXTable(peptideTableMdl) {
            protected JTableHeader createDefaultTableHeader() {
                return new JTableHeader(columnModel) {
                    public String getToolTipText(MouseEvent e) {
                        java.awt.Point p = e.getPoint();
                        int index = columnModel.getColumnIndexAtX(p.x);
                        int realIndex = columnModel.getColumn(index).getModelIndex();
                        String tip = (String) peptideTableToolTips.get(realIndex);
                        return tip;
                    }
                };
            }
        };

        TableConfig.setColumnWidths(peptideTbl, new double[]{1, 8.0, 4.0});

        TableColumnModel tcm = peptideTbl.getColumnModel();
        tcm.getColumn(0).setCellRenderer(new TableConfig.CustomTableCellRenderer(SwingConstants.RIGHT));
        //tcm.getColumn(2).setCellRenderer(new JSparklinesBarChartTableCellRenderer(PlotOrientation.HORIZONTAL, 1.0, true));

        // Sort the peptide table by the number of peptide hits
        peptideTbl.setAutoCreateRowSorter(true);
        peptideTbl.getRowSorter().toggleSortOrder(2);
        peptideTbl.getRowSorter().toggleSortOrder(2);

        // register list selection listener
        peptideTbl.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                refreshPsmTable();
            }
        });

        // Single selection only
        peptideTbl.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        peptideTbl.setSelectionBackground(new Color(130, 207, 250));

        // Add nice striping effect
        peptideTbl.addHighlighter(TableConfig.getSimpleStriping());

        // Set the column control visible.
        peptideTbl.setColumnControlVisible(true);
    }

    /**
     * This method sets up the PSM results table.
     */
    private void setupPsmTableProperties() {
        // PSM table
        final TableModel psmTableMdl = new DefaultTableModel() {
            {
                setColumnIdentifiers(new Object[]{"#", "Charge", "Matched Ions [%]"});
            }

            public boolean isCellEditable(int row, int col) {
                return false;
            }

            public Class<?> getColumnClass(int columnIndex) {
                switch (columnIndex) {
                    case 0:
                    case 1:
                        return Integer.class;
                    case 2:
                        return Double.class;
                    default:
                        return String.class;
                }
            }
        };

        psmTableToolTips = new ArrayList<String>();
        psmTableToolTips.add("PSM Index");
        psmTableToolTips.add("Spectrum Charge");
        psmTableToolTips.add("Matched Ions Ratio (Observed / Total Possible Ions)");

        psmTbl = new JXTable(psmTableMdl) {
            protected JTableHeader createDefaultTableHeader() {
                return new JTableHeader(columnModel) {
                    public String getToolTipText(MouseEvent e) {
                        java.awt.Point p = e.getPoint();
                        int index = columnModel.getColumnIndexAtX(p.x);
                        int realIndex = columnModel.getColumn(index).getModelIndex();
                        String tip = (String) psmTableToolTips.get(realIndex);
                        return tip;
                    }
                };
            }
        };

        // adjust column widths
        TableConfig.setColumnWidths(psmTbl, new double[]{1, 3.0, 6.0});

        // Get table column model
        final TableColumnModel tcm = psmTbl.getColumnModel();

        // Apply custom cell renderers/highlighters to columns
        tcm.getColumn(0).setCellRenderer(new TableConfig.CustomTableCellRenderer(SwingConstants.RIGHT));
        tcm.getColumn(1).setCellRenderer(new TableConfig.CustomTableCellRenderer(SwingConstants.CENTER, "+0"));
        tcm.getColumn(2).setCellRenderer(new JSparklinesBarChartTableCellRenderer(PlotOrientation.HORIZONTAL, 100.0, new Color(110, 196, 97)));
        ((JSparklinesBarChartTableCellRenderer) tcm.getColumn(2).getCellRenderer()).showNumberAndChart(true, 40, new Font("Arial", Font.PLAIN, 12), 0);

        // Auto row sorter
        psmTbl.setAutoCreateRowSorter(true);

        // Register list selection listener
        psmTbl.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
            @Override
            public void valueChanged(ListSelectionEvent e) {
                refreshSpectrumPanel();
            }
        });

        // Only one row is selectable
        psmTbl.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        psmTbl.setSelectionBackground(new Color(130, 207, 250));

        // Add nice striping effect
        psmTbl.addHighlighter(TableConfig.getSimpleStriping());

        // Set column control visible
        psmTbl.setColumnControlVisible(true);
    }

    /**
     * Method to refresh protein family contents.
     */
    protected void refreshProteinFamilyTable() {
        int i = 1;

        if (tagSearchResult != null) {
            TableConfig.clearTable(proteinFamTbl);
            int maxSpecCount = 0;

            for (Entry<String, ProteinFamilyHit> entry : tagSearchResult.getResultMap().entrySet()) {

                ProteinFamilyHit proteinFamilyHit = entry.getValue();
                maxSpecCount = Math.max(maxSpecCount, proteinFamilyHit.getUniqueSpectralCount());

                ((DefaultTableModel) proteinFamTbl.getModel()).addRow(new Object[]{
                            i++,
                            proteinFamilyHit.getName(),
                            proteinFamilyHit.getUniqueSpectralCount()});
            }
            proteinFamTbl.getSelectionModel().setSelectionInterval(0, 0);

            if (proteinFamTbl.getRowCount() > 0) {
                TableColumnModel tcm = proteinFamTbl.getColumnModel();
                tcm.getColumn(2).setCellRenderer(new JSparklinesBarChartTableCellRenderer(PlotOrientation.HORIZONTAL, (double) maxSpecCount, new Color(110, 196, 97)));
                ((JSparklinesBarChartTableCellRenderer) tcm.getColumn(2).getCellRenderer()).showNumberAndChart(true, 50, new Font("Arial", Font.PLAIN, 12), 0);
            }
        }
    }

    /**
     * Method to refresh protein table contents.
     */
    protected void refreshProteinTable() {

        int i = 1;
        int protFamilyRow = proteinFamTbl.getSelectedRow();

        if (protFamilyRow != -1) {
            familyName = (String) proteinFamTbl.getValueAt(protFamilyRow, proteinFamTbl.convertColumnIndexToView(1));

            TableConfig.clearTable(proteinTbl);

            TreeMap<String, ProteinHit> proteinHits = tagSearchResult.getProteinFamilyHit(familyName).getProteinHits();
            for (Entry<String, ProteinHit> entry : proteinHits.entrySet()) {

                ProteinHit proteinHit = entry.getValue();

                // Protein species
                String desc = proteinHit.getDescription();
                String[] split = desc.split(" OS=");
                if (split.length > 1) {
                    proteinHit.setDescription(split[0]);
                    String species = split[1].contains("GN=") ? split[1].substring(0, split[1].indexOf(" GN=")) : split[1];
                    proteinHit.setSpecies(species);
                }

                ((DefaultTableModel) proteinTbl.getModel()).addRow(new Object[]{
                            i++,
                            proteinHit.getAccession(),
                            proteinHit.getDescription(),
                            proteinHit.getSpecies(),
                            proteinHit.getMolWeight()});
            }
            proteinTbl.getSelectionModel().setSelectionInterval(0, 0);
        }
    }

    /**
     * This method updates the results in the panel.
     *
     * @param tagSearchResult The search result
     */
    public void updateResults(TagSearchResult tagSearchResult) {
        this.tagSearchResult = tagSearchResult;
        refreshProteinFamilyTable();
        refreshProteinTable();
        refreshPeptideTable();
        refreshPsmTable();
    }

    /**
     * Method to refresh peptide table contents.
     */
    protected void refreshPeptideTable() {
        TableConfig.clearTable(peptideTbl);

        int protRow = proteinTbl.getSelectedRow();
        if (protRow != -1) {
            String actualAccession = (String) proteinTbl.getValueAt(protRow, proteinTbl.convertColumnIndexToView(1));
            ProteinHit proteinHit = tagSearchResult.getProteinFamilyHit(familyName).getProteinHits().get(actualAccession);
            List<PeptideHit> peptideHits = proteinHit.getPeptideHitList();

            int i = 1, maxSpecCount = 0;
            for (PeptideHit peptideHit : peptideHits) {
                int specCount = peptideHit.getSpectrumMatches().size();
                maxSpecCount = Math.max(maxSpecCount, specCount);
                ((DefaultTableModel) peptideTbl.getModel()).addRow(new Object[]{
                            i++,
                            peptideHit.getSequence(),
                            specCount});
            }
            peptideTbl.getSelectionModel().setSelectionInterval(0, 0);

            TableColumnModel tcm = peptideTbl.getColumnModel();
            tcm.getColumn(2).setCellRenderer(new JSparklinesBarChartTableCellRenderer(PlotOrientation.HORIZONTAL, (double) maxSpecCount, new Color(110, 196, 97)));
            ((JSparklinesBarChartTableCellRenderer) tcm.getColumn(2).getCellRenderer()).showNumberAndChart(true, 50, new Font("Arial", Font.PLAIN, 12), 0);
        }
    }

    /**
     * Method to refresh PSM table contents.
     */
    protected void refreshPsmTable() {
        TableConfig.clearTable(psmTbl);

        int protRow = proteinTbl.getSelectedRow();
        if (protRow != -1) {
            String accession = (String) proteinTbl.getValueAt(protRow, proteinTbl.convertColumnIndexToView(1));
            int pepRow = peptideTbl.getSelectedRow();
            if (pepRow != -1) {
                String sequence = (String) peptideTbl.getValueAt(pepRow, peptideTbl.convertColumnIndexToView(1));
                PeptideHit peptideHit = tagSearchResult.getProteinFamilyHit(familyName).getProteinHits().get(accession).getPeptideHits().get(sequence);
                indexPsmMap = new HashMap<Integer, PeptideSpectrumMatch>();
                DefaultTableModel psmTblMdl = (DefaultTableModel) psmTbl.getModel();
                int i = 1;
                List<PeptideSpectrumMatch> spectrumMatches = new ArrayList<PeptideSpectrumMatch>(peptideHit.getSpectrumMatches().values());
                for (PeptideSpectrumMatch psm : spectrumMatches) {
                    indexPsmMap.put(i, psm);
                    psmTblMdl.addRow(new Object[]{
                                i++,
                                psm.getCharge(),
                                psm.getMatchedIonsRatio()
                            });
                }
                psmTbl.getSelectionModel().setSelectionInterval(0, 0);
            }
        }
    }

    protected void refreshSpectrumPanel() {
        int protRow = proteinTbl.getSelectedRow();
        if (protRow != -1) {
            int pepRow = peptideTbl.getSelectedRow();
            if (pepRow != -1) {
                int psmRow = psmTbl.getSelectedRow();
                if (psmRow != -1) {
                    // clear the spectrum panel
                    while (spectrumJPanel.getComponents().length > 0) {
                        spectrumJPanel.remove(0);
                    }
                    String sequence = (String) peptideTbl.getValueAt(pepRow, peptideTbl.convertColumnIndexToView(1));
                    int index = psmTbl.convertRowIndexToModel(psmRow);
                    PeptideSpectrumMatch currentPsm = indexPsmMap.get(index + 1);
                    // Get the corresponding spectrum.
                    if (querySpectra == null) {
                        querySpectra = mainFrame.getQuerySpectra();
                    }

                    MascotGenericFile mgf = querySpectra.get(currentPsm.getSpectrumTitle());

                    // convert the spectrum
                    ArrayList<Charge> precursorCharges = new ArrayList<Charge>();
                    precursorCharges.add(new Charge(mgf.getCharge(), Charge.PLUS));
                    HashMap<Double,Peak> peakMap = new HashMap<Double, Peak>();
                    HashMap<Double,Double> mgfPeaks = mgf.getPeaks();
                    Iterator<Double> iterator = mgfPeaks.keySet().iterator();
                    while (iterator.hasNext()) {
                        Double mass = iterator.next();
                        peakMap.put(mass, new Peak(mass, mgfPeaks.get(mass)));
                    }
                    MSnSpectrum currentSpectrum = new MSnSpectrum(2, new Precursor(0.0, mgf.getPrecursorMZ(), precursorCharges), mgf.getTitle(), peakMap, mgf.getFilename());
                    
                    specPnl = new SpectrumPanel(
                                    currentSpectrum.getMzValuesAsArray(), currentSpectrum.getIntensityValuesAsArray(),
                                    mgf.getPrecursorMZ(), mgf.getCharge() + "+",
                                    "", 40, false, false, false, 2, false);

                    mainFrame.updateAnnotationMenus(mgf.getCharge());

                    // add the annotations
                    SpectrumAnnotator spectrumAnnotator = new SpectrumAnnotator();

                    // Get the annotation preferences
                    AnnotationPreferences annotationPreferences = mainFrame.getAnnotationPreferences();

                    // show annotated peaks in foreground, non-annotated in background
                    specPnl.showAnnotatedPeaksOnly(!annotationPreferences.showAllPeaks());

                    ArrayList<String> proteins = new ArrayList<String>();
                    proteins.add("Dummy");

                    Peptide currentPeptide = new Peptide(sequence, proteins, new ArrayList<ModificationMatch>()); // @TODO: add ptms!!
                    
                    ArrayList<IonMatch> annotations = spectrumAnnotator.getSpectrumAnnotation(
                            annotationPreferences.getIonTypes(),
                            annotationPreferences.getNeutralLosses(),
                            annotationPreferences.getValidatedCharges(),
                            mgf.getCharge(),
                            currentSpectrum, currentPeptide,
                            currentSpectrum.getIntensityLimit(0.0), // @TODO: should not be hardcoded?
                            0.5, // @TODO: get fragment ion mass error from the search parameters!
                            false);
                    
                    specPnl.setAnnotations(SpectrumAnnotator.getSpectrumAnnotation(annotations));

                    // add de novo sequencing
                    specPnl.addAutomaticDeNovoSequencing(currentPeptide, annotations,
                            PeptideFragmentIon.B_ION,
                            PeptideFragmentIon.Y_ION,
                            annotationPreferences.getDeNovoCharge(),
                            annotationPreferences.showForwardIonDeNovoTags(),
                            annotationPreferences.showRewindIonDeNovoTags());

                    spectrumJPanel.removeAll();
                    spectrumJPanel.add(specPnl, cc.xy(2, 2));
                    spectrumJPanel.revalidate();
                    spectrumJPanel.repaint();
                }
            }
        }
    }
}
